package edu.avans.hartigehap.service.jpa;

import java.util.ArrayList;
import java.util.Date;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Random;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;

import edu.avans.hartigehap.repository.*;
import edu.avans.hartigehap.service.*;
import edu.avans.hartigehap.domain.*;
import edu.avans.hartigehap.domain.decorator.AbstractMenuItem;
import edu.avans.hartigehap.domain.decorator.TestIngredient;

@Service("billService")
@Repository
@Transactional(rollbackFor = StateException.class)
public class BillServiceImpl implements BillService {
	final Logger logger = LoggerFactory.getLogger(BillServiceImpl.class);

	@Autowired
	private RestaurantRepository restaurantRepository;
	@Autowired
	private OrderRepository orderRepository;
	@Autowired
	private LocalBillRepository localBillRepository;
	@Autowired
	private InternetBillRepository internetBillRepository;
	@Autowired
	private MenuItemRepository menuItemRepository;
	@Autowired
	private DiscountRepository discountRepository;

	@Autowired
	private RestaurantService restaurantService;
	@Autowired
	private CustomerService customerService;

	@Transactional(readOnly=true)
	public List<LocalBill> findAll() {
		return Lists.newArrayList(localBillRepository.findAll());
	}
	
	@Transactional(readOnly=true)
	public Bill findBillById(Long billId) {
		Bill bill = localBillRepository.findOne(billId);
		if(bill == null)
			bill = internetBillRepository.findOne(billId);
		
		if(bill == null)
			logger.info("Not found bill " + billId);
		else
			logger.info("Found bill " + billId);
			
		return bill;
	}

	
	public void billHasBeenPaid(Bill bill) throws StateException {
		bill.paid();
	}
	

	@Transactional(readOnly=true)
	public List<Bill> findSubmittedBillsForRestaurant(Restaurant restaurant) {
	// a query created using a repository method name
	List<LocalBill> submittedLocalBillsList = localBillRepository.
			findByBillStatusAndDiningTableRestaurant(
					LocalBill.BillStatus.SUBMITTED, 
					restaurant,
					new Sort(Sort.Direction.ASC, "submittedTime"));
	
	List<InternetBill> submittedInternetBillsList = internetBillRepository.
			findByBillStatusAndRestaurant(
					InternetBill.BillStatus.SUBMITTED, 
					restaurant,
					new Sort(Sort.Direction.ASC, "submittedTime"));

	List<Bill> submittedBillsList = new ArrayList<Bill>();
	submittedBillsList.addAll(submittedLocalBillsList);
	submittedBillsList.addAll(submittedInternetBillsList);
	return submittedBillsList;

	}
	
	public Long createInternetBill(String restaurantName){
		Restaurant restaurant = restaurantRepository.findOne(restaurantName);
		List<Discount> discounts = discountRepository.findByActive(true);
		InternetBill internetBill;
		List<Discount> currentdiscounts = new ArrayList<Discount>();
		for(Discount d : discounts)
		{			
			if(compareDate(new DateTime(d.getDate())))
			{
				currentdiscounts.add(d);
			}
		}
		if(currentdiscounts.size() > 1)
		{
			internetBill = new InternetBill(discounts.get(new Random().nextInt(discounts.size())));
		}
		else
		{
			internetBill = new InternetBill(discounts.get(0));
		}

		internetBill.setRestaurant(restaurant);
		internetBill = (InternetBill) save(internetBill);
		restaurant.getInternetBills().add(internetBill);
		logger.debug("InternetBill created: " + internetBill.getId());
		return internetBill.getId();
	}

	public boolean compareDate(DateTime date)
	{
		boolean result = false;
		DateTime rightNow = new DateTime();

		//same year
		if(rightNow.getYear() == date.getYear())
		{
			if(rightNow.getMonthOfYear() == date.getMonthOfYear())
			{
				if(rightNow.getDayOfMonth() == date.getDayOfMonth())
				{
					result = true;
				}
			}
		}
		return result;
	}

	@Override
	public Bill save(Bill bill) {
		if(bill instanceof InternetBill)
			return internetBillRepository.save((InternetBill)bill);
		else
			return localBillRepository.save((LocalBill)bill);
	}

	public void addOrderItem(Bill bill, String menuItemName) throws StateException {
		MenuItem menuItem = menuItemRepository.findOne(menuItemName);
		bill.getCurrentOrder().addOrderItem(menuItem);
		if(bill instanceof InternetBill)
		{
			bill.getCurrentOrder().fill();
		}
	}
	
	public void deleteOrderItem(Bill bill, String menuItemName) throws StateException {
		MenuItem menuItem = menuItemRepository.findOne(menuItemName);
		bill.getCurrentOrder().deleteOrderItem(menuItem);
		if(bill instanceof InternetBill && bill.getCurrentOrder().isEmpty())
		{
			bill.getCurrentOrder().empty();
		}
	}
	
	public void submitOrder(Bill bill, Customer customer, Restaurant restaurant)
		throws StateException, EmptyBillException {

		/*
		Collection<Customer> customers = restaurant.getCustomers();
		customers.add(customer);
		
		List<Customer> newCustomers = new ArrayList<Customer>();
		newCustomers = (List<Customer>) customers;
		restaurant.setCustomers(newCustomers);
		//bill.setCustomer(customer);
		*/
		
		customer.setRestaurants(Arrays.asList(new Restaurant[] {restaurant}));
		//restaurant.getCustomers().add(customer);
		customer.getBills().add(bill);
		bill.submitOrder();
		save(bill);
		restaurantService.save(restaurant);
		customerService.save(customer);
		// for test purposes: to cause a rollback, throw new StateException("boe");
	}
	
	public void submitBill(Bill bill)
		throws StateException, EmptyBillException {
		bill.submit();
	}

	public void delete(Long id) {
		localBillRepository.delete(id);
	}

	@Override
	public void addOrderItemIngredient(Bill bill, TestIngredient testIngredient, MenuItem menuItem)
			throws StateException {
		// TODO Auto-generated method stub
		bill.getCurrentOrder().addOrderItemIngredient(menuItem, testIngredient);
		if(bill instanceof InternetBill)
		{
			bill.getCurrentOrder().fill();
		}
		
	}
}
